package com.yangming.springboot.deepin.playTest;

import javax.xml.soap.Node;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

/**
 * @创建人 ym
 * @创建时间 2021/4/9 0009
 * @描述
 **/
public class Mutex implements Lock {
    //自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer{
        //是否处于占用状态 1为占用，0无占用
        protected  boolean isHeldExclusively(){
            return getState() == 1;
        }
        //状态为0的时候，获取锁
        public boolean tryAcquire(int acquires){
            if (compareAndSetState(0, 1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int release){
            if (getState() == 0) throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        //同步器中acquire方法
//        public final void acquire(int arg){
//            if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
//                selfInterrupt();
//            }
//        }
        //同步器中的acquireQueued方法
        private final boolean acquireQueued(final Node node, int arg){
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;){
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)){
                        setHead(node);
                        p.next = null;
                        failed = false;
                        return interrupted;
                    }
                    if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){
                        interrupted = true;
                    }
                }
            }finally{
                if (failed){
                    cancelAcquire(node);
                }
            }
        }

        public final boolean release(int arg){
            if (tryRelease(arg)){
                Node h = head;
                if (h = !null && h.waitStatus != 0){
                    //唤醒处于等待状态的线程
                    unparkSuccessor(h);
                }
                return true;
            }
            return false;
        }

        private Node addWaiter(Node mode){
            Node node = new Node(Thread.currentThread(), mode);
            Node pred = tail;
            if (pred != null){
                node.prev = pred;
                if (compareandsetTail(pred, node)){
                    pred.next = node;
                    return node;
                }
            }
            //如果第一次获取不到同步队列就直接进入自循环
            enq(node);
            return node;
        }

        private Node enq(final Node node){
            //进入死循环，并且线程阻塞
            for (;;){
                Node t = tail;
                if (t == null){
                    if (compareAndSetHead(new Node())){
                        tail = head;
                    }
                }else{
                    node.prev = t;
                    if (compareAndSetTail(t, node)){
                        t.next = node;
                        return t;
                    }
                }
            }
        }

        Condition newCondition(){
            return new ConditionObject();
        }

        //获取共享同步状态
        public final void acquireShared(int arg){
            if (tryQcquireShared(arg) < 0){
                doAcquireShared(arg);
            }
        }

        private void doAcquireShared(int arg){
            final Node node = addWaiter(Node.SHARED);
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;){
                    final Node p = node.preedecessor();
                    if (p == head){
                        int r = tryAcquireShared(arg);
                        if (r >= 0){
                            setHeadAndPropagate(node, r);
                            p.next = null;
                            if (interrupted){
                                selfInterrupt();
                            }
                            failed = false;
                            return;
                        }
                    }
                    if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){
                        interrupted = true;
                    }
                }
            }finally{
                if (failed){
                    cacelAcquire(node);
                }
            }
        }

    }

    public final boolean releaseShared(int arg){
        if (tryReleaseShared(arg)){
            doReleaseShared();
            return true;
        }
        return false;
    }

    private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException{
        long lastTime = System.nanoTime();
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;){
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)){
                    setHead(node);
                    p.next = null;
                    failed = false;
                    return true;
                }
                if (nanosTimeout <= 0){
                    return false;
                }
                if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold){
                    LockSupport.parkNanos(this, nanosTimeout);
                }
                long now = System.nanoTime();
                nanosTimeout -= now - lastTime;
                lastTime = now;
                if (Thread.interrupted()){
                    throw new InterruptedException();
                }
            }
        }finally{
            if (failed){
                cancelAcquire(node);
            }
        }
    }

    //将操作代理到sync上
    private final Sync sync = new Sync();
    public void lock(){
        sync.acquire(1);
    }
    public boolean tryLock(){
        return sync.tryAcquire(1);
    }
    public void unlock(){
        sync.release(1);
    }
    public Condition newCondition(){
        return sync.newCondition();
    }
    public boolean isLocked(){
        return sync.isHeldExclusively();
    }
    public boolean hasQueuedThreads(){
        return sync.hasQueuedThreads();
    }
    public void lockInterruptibly() throws InterruptedException{
        sync.acquireInterruptibly(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException{
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }


}
